import { Button } from "antd";
import { memo, useContext } from "react";
import {
  clsx,
  getRelationPath,
  invokeFunc,
  toLevelPath,
  wrapperCls,
} from "../utils";
import { RuleTreeContext, RuleTreePropsContext } from "./RuleTreeContext";
import DragItem from "./DragItem";
import DropIndicator from "./DropIndicator";
import { CopySvg, DeleteSvg } from "../utils/constant";
import {
  addRuleGroup,
  addRuleItem,
  moveRuleItem,
  removeRuleItem,
} from "../utils/model";
import { useOutterComponents } from "../utils/hooks";
import type { FieldNames } from "../types";
import { fieldNamesTreeMap } from "../utils/global";
import styled from "styled-components";

export const WrapperActionDom = styled.div`
  display: flex;
  align-items: center;
  margin-left: 4px;
`;

export const Gap = styled.div<{ $marginBottom: number }>`
  margin-bottom: ${(props) => props.$marginBottom}px;
`;

function RuleItem(props: {
  children: React.ReactNode;
  path: (string | number)[];
  index: number;
  isLeaf?: boolean;
  overMaxCount?: boolean;
}) {
  const { Form } = useOutterComponents();
  const form = Form.useFormInstance();
  const {
    onChange,
    actionRender,
    disabled,
    itemRender,
    gap,
    uid,
    defaultRelationValue,
  } = useContext(RuleTreePropsContext);
  const { prefixCls } = useContext(RuleTreeContext);
  const { relation: RelationKey, children: ChildrenKey } =
    fieldNamesTreeMap.get(uid) as Required<FieldNames>;
  const isRoot = props.path.length === 1;
  const levelPath = toLevelPath(props.path);
  const cls = wrapperCls(prefixCls);

  const copyDom = invokeFunc(() => {
    return (
      <Button
        key={"copy"}
        size="small"
        type="text"
        disabled={disabled || props.overMaxCount}
        style={{
          paddingTop: 2,
        }}
        onClick={() => {
          const currentList = form.getFieldValue(props.path) || [];
          addRuleItem(form, props.path, currentList[props.index], props.index);
          onChange?.(form.getFieldsValue(true));
        }}
        icon={CopySvg}
      />
    );
  });

  const removeDom = invokeFunc(() => {
    return (
      <Button
        key={"remove"}
        size="small"
        type="text"
        disabled={disabled}
        style={{
          paddingTop: 2,
        }}
        onClick={() => {
          removeRuleItem(form, props.path, props.index, isRoot);
          onChange?.(form.getFieldsValue(true));
        }}
        icon={DeleteSvg}
      />
    );
  });

  const actionDoms = invokeFunc(() => {
    // 非叶子节点没有action doms
    if (!props.isLeaf) {
      return null;
    }

    if (actionRender) {
      return actionRender(
        { copyDom, removeDom },
        {
          add(data, index) {
            addRuleItem(form, props.path, data, index);
            onChange?.(form.getFieldsValue(true));
          },
          addGroup(defaultGroupData, insertIndex) {
            const mergedGroupData = defaultGroupData || {
              [RelationKey]: defaultRelationValue,
            };
            addRuleGroup(
              form,
              props.path,
              ChildrenKey,
              mergedGroupData,
              insertIndex
            );
            onChange?.(form.getFieldsValue(true));
          },
          remove(index) {
            const removeIndex = index === undefined ? props.index : index;
            removeRuleItem(form, props.path, removeIndex, isRoot);
            onChange?.(form.getFieldsValue(true));
          },
          move(to) {
            moveRuleItem(
              form,
              {
                levelPath: levelPath,
                index: props.index,
              },
              to,
              ChildrenKey
            );
            onChange?.(form.getFieldsValue(true));
          },
          get() {
            return form.getFieldValue(props.path);
          },
          getGroupData() {
            return {
              [RelationKey]: form.getFieldValue(
                getRelationPath(props.path, RelationKey)
              ),
              [ChildrenKey]: form.getFieldValue(props.path),
            };
          },
          getCurrentRowData() {
            return form.getFieldValue([...props.path, props.index]) || {};
          },
          setCurrentRowData(value = {}) {
            const currentRowData =
              form.getFieldValue([...props.path, props.index]) || {};
            form.setFieldValue([...props.path, props.index], {
              ...currentRowData,
              ...value,
            });
            onChange?.(form.getFieldsValue(true));
          },
        },
        {
          levelPath: levelPath,
          index: props.index,
          isLeaf: !!props.isLeaf,
          disabled: !!disabled,
          overMaxCount: !!props.overMaxCount,
        }
      );
    }

    return [copyDom, removeDom];
  });

  return (
    <div
      className={clsx(`${cls}-item`, {
        [`${cls}-item-leaf`]: props.isLeaf,
        [`${cls}-item-inner`]: !isRoot,
      })}
    >
      <DropIndicator
        index={props.index}
        levelPath={levelPath}
        overMaxCount={props.overMaxCount}
      >
        <div className={`${cls}-indicator`} />
      </DropIndicator>
      <DragItem
        levelPath={levelPath}
        index={props.index}
        isLeaf={props.isLeaf}
        onMove={({ dragLevelPath, dragIndex, dropLevelPath, dropIndex }) => {
          moveRuleItem(
            form,
            { levelPath: dragLevelPath, index: dragIndex },
            { levelPath: dropLevelPath, index: dropIndex },
            ChildrenKey
          );
          // notice: 存在校验错触发全局校验
          if (
            form
              .getFieldsError()
              .some((item) => !!item.errors.length || !!item.warnings.length)
          ) {
            form.validateFields();
          }
          onChange?.(form.getFieldsValue(true));
        }}
      >
        {itemRender ? (
          itemRender(
            {
              itemDom: props.children,
              actionDom: actionDoms,
            },
            form.getFieldValue([...props.path, props.index]),
            {
              levelPath: levelPath,
              isLeaf: !!props.isLeaf,
              index: props.index,
            }
          )
        ) : (
          <>
            <span className={`${cls}-item-content`}>{props.children}</span>
            {props.isLeaf && (
              <WrapperActionDom className={`${cls}-item-action`}>
                {actionDoms}
              </WrapperActionDom>
            )}
          </>
        )}
      </DragItem>
      <Gap
        className={clsx(`${cls}-item-gap`)}
        $marginBottom={(gap as [number, number])[1]}
      />
    </div>
  );
}

export default memo(RuleItem, (prev, next) => {
  return (
    prev.children === next.children &&
    prev.path.join("-") === next.path.join("-") &&
    prev.index === next.index &&
    prev.isLeaf === next.isLeaf &&
    prev.overMaxCount === next.overMaxCount
  );
}) as typeof RuleItem;
